package com.ltxtiyu.video.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.ltxtiyu.video.cacheDao.ConfigCacheDao;
import com.ltxtiyu.video.cacheDao.UserCacheDao;
import com.ltxtiyu.video.common.*;
import com.ltxtiyu.video.dao.ltx.TokenStoreDao;
import com.ltxtiyu.video.dao.ltx.UserDao;
import com.ltxtiyu.video.entity.TokenStore;
import com.ltxtiyu.video.entity.User;
import com.ltxtiyu.video.service.app.OauthService;
import com.ltxtiyu.video.tool.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 登陆认证相关
 */
@Service
@Transactional
public class OauthServiceImpl implements OauthService {
    private final static Logger LOGGER = LoggerFactory.getLogger(OauthServiceImpl.class);
    @Autowired
    UserCacheDao userCacheDao;
    @Autowired
    UserDao userDao;
    @Autowired
    TokenStoreDao tokenStoreDao;
    @Autowired
    ConfigCacheDao configCacheDao;

    /**
     * 发送验证码
     * @param map
     * @return
     */
    @Override
    public String captcha(Map<String, String> map) {
        String mobile = ObjectTool.stringOrNull( map.get("mobile"));
        String type = ObjectTool.stringOrNull( map.get("type"));
        User user = userDao.selectByMobile(mobile);

        // 不同的提示内容发送
        if (ApiConstant.CAPTCHA_MAP.containsKey(mobile)) {
            String[] codeExpireTime = ApiConstant.CAPTCHA_MAP.get(mobile)
                    .split(":");
            if (System.currentTimeMillis() < Long.parseLong(codeExpireTime[1])) {
                // 验证码重复请求
                return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_REPEAT_ERROR);
            }
        }
        // 验证码
        int code = new Random().nextInt(899999) + 100000;
        // 60秒有效期
        ApiConstant.CAPTCHA_MAP.put(mobile, code + ":"
                + (new Date().getTime() + 60000));

        boolean sendStatus = false;
        // 1：注册；2：忘记密码
        if ("1".equals(type)) {
            if (user != null && user.getRegSrc() != null) {
                return JsonTool.genJson(RetEnum.OAUTH_CHECK_REGISTER_EXIST);    // 用户已存在
            }
            sendStatus = SmsTool.sendSmsCaptcha(mobile, "您好，您的验证码为：" + code);
        } else if ("2".equals(type)) {
            sendStatus = SmsTool.sendSmsCaptcha(mobile, "您好，您的验证码为：" + code
                    + "（请勿将验证码转告他人）");
        }

        if (sendStatus) {
            // 发送验证码成功
            return JsonTool.genJson(RetEnum.SUCCESS);
        }
        // 验证码发送失败
        return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_SEND_FAIL);
    }

    /**
     * 注册
     * @param stringObjectMap
     * @return
     */
    @Override
    public String register(Map<String, String> stringObjectMap) {
        String channel = ObjectTool.stringOrNull( stringObjectMap.get("channel"));
        String mobile = ObjectTool.stringOrNull( stringObjectMap.get("mobile"));
        String captcha = ObjectTool.stringOrNull( stringObjectMap.get("captcha"));
        String deviceToken = ObjectTool.stringOrNull( stringObjectMap.get("deviceToken"));
        // 校验参数
        if(mobile == null){
            return JsonTool.genJson(RetEnum.MOBILE_IS_BLANK);
        }
        if(captcha == null){
            return JsonTool.genJson(RetEnum.CAPTCHA_IS_BLANK);
        }
        Integer platform = 0;
        if(StringUtils.isNotBlank(channel)){
            platform = Integer.valueOf(channel);
        }

        // 校验验证码
        if (!ApiConstant.CAPTCHA_MAP.containsKey(mobile)) { // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }
        String[] values = ApiConstant.CAPTCHA_MAP.get(mobile).split(":");
        if (!values[0].equals(captcha)) {   // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }


        User user = userDao.selectByMobile(mobile);
        Map<String, Object> result = new HashMap<>();
        if(user != null){
            if(user.getStatus().intValue() == CodeTypeConstant.COMMON_TYPE_0.intValue()){   // 用户被封停
                return JsonTool.genJson(RetEnum.OAUTH_CHECK_BANNED);
            }
            user.setDeviceToken(deviceToken);
            userCacheDao.updateByPrimaryKeySelective(user);
            result.put("isRegister",0);     // 是登陆
        }else {
            user = new User();
            user.setMobile(mobile);
            user.setDeviceToken(deviceToken);
            user.setPlatform(platform);
            user.setRegSrc(platform);
            user.setCreateTime(new Date());
            user.setStatus(1);  // 默认设置激活
            userCacheDao.insertSelective(user);
            LOGGER.info(">>>>>>>>>>>>>>>用户注册成功! mobile:{}", user.getMobile());
            result.put("isRegister",1);     // 是注册
        }
        if(user.getId() == null){
            return JsonTool.genJson(RetEnum.FAIL);  // 操作失败
        }
        // 设置token
        String type = SecurityConstant.TOKEN_TYPE_APP;
        TokenStore oauthToken = getOauthToken(user.getId(), type);
        result.put("oauthToken",oauthToken.getOauthToken());
        result.put("refreshToken",oauthToken.getRefreshToken());
        result.put("userId",user.getId());
        result.put("mobile",mobile);
        return JsonTool.genJson(RetEnum.SUCCESS,result);
    }

    /**
     * 密码登陆
     * @param stringObjectMap
     * @return
     */
    @Override
    public String loginByPassword(Map<String, String> stringObjectMap) {
        String mobile = ObjectTool.stringOrNull( stringObjectMap.get("mobile"));
        String password = ObjectTool.stringOrNull( stringObjectMap.get("password"));
        Integer channel = ObjectTool.numberOrNull( stringObjectMap.get("channel"));
        String deviceToken = ObjectTool.stringOrNull( stringObjectMap.get("deviceToken"));

        Map<String, Object> result = new HashMap<>();
        User user = userDao.selectByMobile(mobile);
        if(user != null){
            if(!password.equals(user.getPassword())){
                return JsonTool.genJson(RetEnum.OAUTH_LOGIN_FAIL);  // 密码错误
            }
            if(user.getStatus().intValue() == CodeTypeConstant.COMMON_TYPE_0.intValue()){   // 用户被封停
                return JsonTool.genJson(RetEnum.OAUTH_CHECK_BANNED);
            }
        }else{
            return JsonTool.genJson(RetEnum.WX_OPEN_ID_ERROR);  // 用户未注册
        }
        if(channel != null){
            user.setPlatform(channel);  // 设置最后一次登录的平台
        }
        user.setDeviceToken(deviceToken);
        userCacheDao.updateByPrimaryKeySelective(user);

        // 设置token
        String type = SecurityConstant.TOKEN_TYPE_APP;
        TokenStore oauthToken = getOauthToken(user.getId(), type);
        result.put("oauthToken",oauthToken.getOauthToken());
        result.put("refreshToken",oauthToken.getRefreshToken());
        result.put("userId",user.getId());
        return JsonTool.genJson(RetEnum.SUCCESS,result);
    }

    /**
     * 微信登陆
     * @param stringObjectMap
     * @return
     */
    @Override
    public String loginByWx(Map<String, String> stringObjectMap) {
        String deviceToken = ObjectTool.stringOrNull( stringObjectMap.get("deviceToken"));
        String openId = ObjectTool.stringOrNull( stringObjectMap.get("openId"));
        String app_access_token = ObjectTool.stringOrNull( stringObjectMap.get("app_access_token"));
        Integer channel = ObjectTool.numberOrNull( stringObjectMap.get("channel"));
        if(openId == null || app_access_token == null){ // 参数错误
            return JsonTool.genJson(RetEnum.REQUEST_PARAM_ERROR);
        }

        /**
         * 查看unionId, 和用户的昵称和头像
         * 微信登录新建用户复用用户微信的昵称和头像
         */
        String unionId = "";
        String nickName = "";
        String headPortraitId = "";
        String headPortraitUrl = "";
        String OSS_ENDPOINT = configCacheDao.selectByCkey(ConfigConstant.OSS_ENDPOINT).getCvalue();
        String ACCESS_ID = configCacheDao.selectByCkey(ConfigConstant.ACCESS_ID).getCvalue();
        String ACCESS_KEY = configCacheDao.selectByCkey(ConfigConstant.ACCESS_KEY).getCvalue();
        String BUCKET_ID = configCacheDao.selectByCkey(ConfigConstant.BUCKET_ID).getCvalue();
        String OSS_CDN = configCacheDao.selectByCkey(ConfigConstant.OSS_CDN).getCvalue();

        // 上传图片用OSS_ENDPOINT
        AliTool aliTool = AliTool.getInstance(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, BUCKET_ID);
        AliTool aliShowTool = AliTool.getInstance(OSS_CDN, ACCESS_ID, ACCESS_KEY, BUCKET_ID);

        String unionidUrl = CodeTypeConstant.UNIONID_URL_APP + "?access_token=" + app_access_token +"&openid=" + openId;
        JSONObject jsonObject = HttpTool.httpRequest(unionidUrl, "GET", null);
        if( StringUtils.isNotBlank((String)jsonObject.get("unionid"))){ // 数据库存储的其实是unionid
            unionId = (String)jsonObject.get("unionid");
        }else{
            LOGGER.info(">>>>>>>>>>>>>>>>>>>>>"+this.getClass().getName()+": 获取unionid失败");
            return JsonTool.genJson(RetEnum.GET_UNIONID_FAIL);  // 获取unionId失败
        }
        if( StringUtils.isNotBlank((String)jsonObject.get("nickname"))){ // 数据库存储的其实是unionid
            nickName = (String)jsonObject.get("nickname");
        }
        if( StringUtils.isNotBlank((String)jsonObject.get("headimgurl"))){ // 数据库存储的其实是unionid
            try{
                String headimgurl = (String)jsonObject.get("headimgurl");
                String imageBase64 = ImageTool.imageUrlToBase64(headimgurl);
                headPortraitId = aliTool.updateSinglePic(aliTool, imageBase64);
                // 查看图片用OSS_CDN
                headPortraitUrl = aliShowTool.getAccessURL(headPortraitId);
            }catch (Exception e){
                LOGGER.error(">>>>>>>>>>>>处理图片,发生错误:{}",e);
            }
        }

        Map<String, Object> result = new HashMap<>();
        User user = userDao.selectByUnionId(unionId);
        Integer userId = null;
        if(user != null){
            if(user.getStatus().intValue() == CodeTypeConstant.COMMON_TYPE_0.intValue()){   // 用户被封停
                return JsonTool.genJson(RetEnum.OAUTH_CHECK_BANNED);
            }
            user.setDeviceToken(deviceToken);
            userCacheDao.updateByPrimaryKeySelective(user);
            result.put("isRegister",0);     // 是登陆
            nickName = user.getNickName();
            if(StringUtils.isNotBlank(user.getHeadPortraitId())){
                headPortraitUrl = aliShowTool.getAccessURL(user.getHeadPortraitId());
            }

        }else{
            user = new User();
            user.setUnionId(unionId);
            user.setCreateTime(new Date());
            user.setPlatform(channel);
            user.setRegSrc(channel);
            user.setDeviceToken(deviceToken);
            user.setStatus(1);      // 要设置, 不然cache库没有
            if(StringUtils.isNotBlank(nickName)){
                user.setNickName(nickName);
            }
            if(StringUtils.isNotBlank(headPortraitId)){
                user.setHeadPortraitId(headPortraitId);
            }
            userCacheDao.insertSelective(user);
            result.put("isRegister",1);     // 是注册
        }
        userId = user.getId();
        if(userId == null){
            return JsonTool.genJson(RetEnum.FAIL);
        }
        result.put("userId",userId);
        // 设置token
        String type = SecurityConstant.TOKEN_TYPE_APP;
        TokenStore oauthToken = getOauthToken(userId, type);
        result.put("oauthToken",oauthToken.getOauthToken());
        result.put("refreshToken",oauthToken.getRefreshToken());
        result.put("mobile",user.getMobile());
        result.put("mobile",user.getMobile());
        result.put("nickName",nickName);
        result.put("headPortraitUrl",headPortraitUrl);
        return JsonTool.genJson(RetEnum.SUCCESS,result);
    }

    /**
     * 忘记密码 | 找回密码 | 修改密码 | 设置密码
     * @param stringObjectMap
     * @return
     */
    @Override
    public String setPassword(Map<String, String> stringObjectMap) {
        String mobile = ObjectTool.stringOrNull( stringObjectMap.get("mobile"));
        String captcha = ObjectTool.stringOrNull( stringObjectMap.get("captcha"));
        String password = ObjectTool.stringOrNull( stringObjectMap.get("password"));
        String deviceToken = ObjectTool.stringOrNull( stringObjectMap.get("deviceToken"));

        User user = userDao.selectByMobile(mobile);
        if(user == null){   // 用户不存在
            return JsonTool.genJson(RetEnum.OAUTH_CHECK_INEXISTENCE);
        }
        // 校验验证码
        if (!ApiConstant.CAPTCHA_MAP.containsKey(mobile)) {
            // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }
        String[] values = ApiConstant.CAPTCHA_MAP.get(mobile).split(":");
        if (!values[0].equals(captcha)) {
            // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }

        // 更新密码
        user.setPassword(password);
        user.setDeviceToken(deviceToken);
        userCacheDao.updateByPrimaryKeySelective(user);
        Map<String, Object> result = new HashMap<>();
        result.put("userId",user.getId());

        return JsonTool.genJson(RetEnum.SUCCESS,result);
    }

    /**
     * 微信登录绑定手机号
     * @param stringObjectMap
     * @return
     */
    @Override
    public String bindMobile(Map<String, String> stringObjectMap) {
        Integer userId = ObjectTool.numberOrNull(stringObjectMap.get("userId"));
        String mobile = ObjectTool.stringOrNull( stringObjectMap.get("mobile"));
        String captcha = ObjectTool.stringOrNull( stringObjectMap.get("captcha"));
        String password = ObjectTool.stringOrNull( stringObjectMap.get("password"));
        String deviceToken = ObjectTool.stringOrNull( stringObjectMap.get("deviceToken"));
        if(mobile == null || captcha == null || password == null || deviceToken == null){
            return JsonTool.genJson(RetEnum.REQUEST_PARAM_ERROR);   // 请求参数错误
        }

        User user = userDao.selectByMobile(mobile);
        if(user != null){
            return JsonTool.genJson(RetEnum.MOBILE_BIND_OTHER_WX);  // 手机号被注册
        }

        // 校验验证码
        if (!ApiConstant.CAPTCHA_MAP.containsKey(mobile)) {
            // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }
        String[] values = ApiConstant.CAPTCHA_MAP.get(mobile).split(":");
        if (!values[0].equals(captcha)) {
            // 验证码错误
            return JsonTool.genJson(RetEnum.OAUTH_CAPTCHA_CHECK_ERROR);
        }

        // 查询unionId
        /*String unionId = "";
        String unionidUrl = CodeTypeConstant.UNIONID_URL_APP + "?access_token=" + app_access_token +"&openid=" + openId;
        JSONObject jsonObject = HttpTool.httpRequest(unionidUrl, "GET", null);
        if( StringUtils.isNotBlank((String)jsonObject.get("unionid"))){ // 数据库存储的其实是unionid
            unionId = (String)jsonObject.get("unionid");
        }else{
            LOGGER.info(">>>>>>>>>>>>>>>>>>>>>"+this.getClass().getName()+": 获取unionid失败");
            return JsonTool.genJson(RetEnum.GET_UNIONID_FAIL);  // 获取unionId失败
        }*/

        User tempUser = userCacheDao.selectByPrimaryKey(userId);
        if(tempUser == null){
            return JsonTool.genJson(RetEnum.WX_OPEN_ID_ERROR);
        }

        user = new User();
        user.setMobile(mobile);
        user.setPassword(password);
        user.setDeviceToken(deviceToken);
        user.setStatus(1);      // 要设置, 不然cache库没有
        userCacheDao.insertSelective(user);
        Map<String, Object> result = new HashMap<>();
        result.put("userId",user.getId());
        return JsonTool.genJson(RetEnum.SUCCESS,result);
    }

    /**
     * 刷新token
     * @param stringObjectMap
     * @return
     */
    @Override
    public String refreshToken(Map<String, String> stringObjectMap) {
        String refreshToken = ObjectTool.stringOrNull( stringObjectMap.get("refreshToken"));
        TokenStore ts = refreshTokenMethod(refreshToken, SecurityConstant.TOKEN_TYPE_APP);
        if (ts != null) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("oauthToken", ts.getOauthToken());
            map.put("refreshToken", ts.getRefreshToken());
            return JsonTool.genJson(RetEnum.SUCCESS, map);
        }
        return JsonTool.genJson(RetEnum.OAUTH_REFRESH_TOKEN_FAIL);
    }

    /**
     * 退出登陆
     * @param stringObjectMap
     * @return
     */
    @Override
    public String logout(Map<String, String> stringObjectMap) {
        String oauthToken = ObjectTool.stringOrNull( stringObjectMap.get("oauthToken"));
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("oauthToken",oauthToken);
        paramMap.put("type",SecurityConstant.TOKEN_TYPE_APP);
        TokenStore tokenStore = tokenStoreDao.selectByOauthToken(paramMap);
        if(tokenStore != null && tokenStore.getUserId() != null){
            User user = userCacheDao.selectByPrimaryKey(tokenStore.getUserId());
            if(user != null){
                user.setDeviceToken("");
                user.setPlatform(-1);
                userCacheDao.updateByPrimaryKeySelective(user);
            }
        }
        return JsonTool.genJson(RetEnum.SUCCESS);
    }

    /**
     * 刷新token
     * @param oldRefreshToken
     * @param type
     * @return
     */
    private TokenStore refreshTokenMethod(String oldRefreshToken, String type) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("oldRefreshToken", oldRefreshToken);
        map.put("type", type);
        TokenStore ts = tokenStoreDao.selectByRefreshToken(map);
        if(ts != null) {
            String oauthToken = DigestUtils.md5Hex(UUID.randomUUID().toString());
            String refreshToken = DigestUtils.md5Hex(oauthToken
                    + System.currentTimeMillis());

            ts.setOauthToken(oauthToken);
            ts.setRefreshToken(refreshToken);
            // 2小时的有效时间过短，改为1年
            Calendar c = Calendar.getInstance();
            c.add(Calendar.YEAR, 1);
            ts.setCreateTime(c.getTime());
            tokenStoreDao.updateByPrimaryKeySelective(ts);
        }
        return ts;
    }

    /**
     * 获取token
     * @param userId
     * @param type
     * @return
     */
    private TokenStore getOauthToken(Integer userId, String type) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userId", userId);
        map.put("type", type);
        tokenStoreDao.deleteByUserId(map);

        TokenStore ts = new TokenStore();
        String oauthToken = DigestUtils.md5Hex(UUID.randomUUID().toString());
        String refreshToken = DigestUtils.md5Hex(oauthToken
                + System.currentTimeMillis());

        ts.setUserId(userId);
        ts.setOauthToken(oauthToken);
        ts.setRefreshToken(refreshToken);
        ts.setType(type);
        // 2小时的有效时间过短，改为1年
        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR, 1);
        ts.setCreateTime(c.getTime());
        tokenStoreDao.insertSelective(ts);
        return ts;
    }
}
